/**
 * Copyright (c) 2010 icer He <icerhe@gmail.com>
 */
package com.icerhe.trigger;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.text.format.DateFormat;
import android.util.Log;

import com.icerhe.trigger.task.AirplaneModeTask;
import com.icerhe.trigger.task.AirplaneModeTaskSetting;
import com.icerhe.trigger.task.AlarmTask;
import com.icerhe.trigger.task.AlarmTaskSetting;
import com.icerhe.trigger.task.CronTask;
import com.icerhe.trigger.task.WifiTask;
import com.icerhe.trigger.task.WifiTaskSetting;

/**
 * @author icer
 *
 */
public class TaskHelper {
	
	public static final String TASK_ACTION = "com.icerhe.autotask.TASK_ACTION";
	public static final String RUN_TASK = "RUN_TASK";
	public static final int INTERVAL = 60;
	
	private static  List<CronTask> cronTaskList = null;
	
	private static final HashMap<String, Class> settingClass = 
		new HashMap<String, Class>();
	
	static {
		settingClass.put(AlarmTask.class.getName(), AlarmTaskSetting.class);
		settingClass.put(AirplaneModeTask.class.getName(), AirplaneModeTaskSetting.class);
		settingClass.put(WifiTask.class.getName(), WifiTaskSetting.class);
		//TODO 加入其它的task类配置,以后设法独立出去
	}
	
	/**
	 * 根据任务类名取得对应的设置类名
	 * @param task
	 * @return
	 */
	public static Class getSettingClass(CronTask task) {
		Class cls = settingClass.get(task.getClass().getName());
		return cls;
	}
	
	/**
	 * 设定下一次task执行的时间
	 * @param context
	 */
	public static void setNextTask(Context context) {
		Log.d(Consts.TAG, "start set next task");
		List<CronTask> taskList = getAllCronTask(context);
		Calendar currentTime = Calendar.getInstance();
		Calendar cal = getNextTrigger(taskList, currentTime, INTERVAL);
		
		Log.d(Consts.TAG, "CurrentTime: "+DateFormat.format("yyyy-MM-dd kk:mm:ss", currentTime));
		
		long atTime;
		if (cal==null) {
			currentTime.set(Calendar.MILLISECOND, 0);
			currentTime.set(Calendar.SECOND, 0);
			currentTime.add(Calendar.MINUTE, Consts.INTERVAL);
			atTime = currentTime.getTimeInMillis();
			Log.d(Consts.TAG, "next task will run at: "+DateFormat.format("yyyy-MM-dd kk:mm:ss", currentTime));
		} else {
			atTime = cal.getTimeInMillis();
			Log.d(Consts.TAG, "next task will run at:"+DateFormat.format("yyyy-MM-dd k:mm:ss", cal));
		}
		
		Intent intent = new Intent(TASK_ACTION);
		Bundle bl = new Bundle();
		bl.putBoolean(RUN_TASK, cal==null?false:true);
		intent.putExtras(bl);
		PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
		AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
		am.set(AlarmManager.RTC_WAKEUP, atTime, sender);
	}
	
	/**
	 * 停止task的运行
	 * @param context
	 */
	public static void cancelTask(Context context) {
		Log.d(Consts.TAG, "cancel task");
		Intent intent = new Intent(TASK_ACTION);
		PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
		AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
		am.cancel(sender);
	}
	
	/**
	 * 根据时间找出应该被运行的Task列表
	 * @param cal 时间
	 */
	public static List<CronTask> getCronTaskByTime(Context context, Calendar cal) {
		List <CronTask> ret = new ArrayList<CronTask>();
		int minute = cal.get(Calendar.MINUTE);
		int hour   = cal.get(Calendar.HOUR_OF_DAY);
		int dom    = cal.get(Calendar.DAY_OF_MONTH);
		int dow    = cal.get(Calendar.DAY_OF_WEEK);
		int month  = cal.get(Calendar.MONTH);
		int year   = cal.get(Calendar.YEAR);
		
		List<CronTask> taskList = getAllCronTask(context);
		
		for(CronTask task : taskList) {
			if ( task.isEnabled() && 
				 task.bYears[year] && 
				 task.bMonths[month] && 
			     task.bDaysOfMonth[dom] && 
			     task.bDaysOfWeek[dow] && 
			     task.bHours[hour] && 
			     task.bMinutes[minute]) {
				ret.add(task);
			}
		}
		
		return ret;
	}
	
	/**
	 * 取得数据库中所有CronTask
	 * @return
	 */
	public static synchronized List<CronTask> getAllCronTask(Context context) {
		Log.d(Consts.TAG, "TaskHelper getAllCronTask()");
	
		if (cronTaskList==null) {
			Log.d(Consts.TAG, "TaskHelper getAllCronTask() query DB");
			ContentResolver resolver = context.getContentResolver();
			Cursor cr = resolver.query(
					CronTask.CONTENT_URI, CronTask.Columns.QUERY_COLUMNS, null, null, null);
			
			ArrayList<CronTask> taskList = new ArrayList<CronTask>();
			
			if (cr.moveToFirst()) {
				do {
					String type = cr.getString(cr.getColumnIndex(CronTask.Columns.TASK_TYPE));
					if (AlarmTask.class.getName().equals(type)) {
						AlarmTask alarmTask = new AlarmTask(cr);
			        	taskList.add(alarmTask);
					} else if (AirplaneModeTask.class.getName().equals(type)) {
						AirplaneModeTask airplaneModeTask = new AirplaneModeTask(cr);
						taskList.add(airplaneModeTask);
					} else if (WifiTask.class.getName().equals(type)) {
						WifiTask wifiTask = new WifiTask(cr);
						taskList.add(wifiTask);
					} 
		        	
		        } while (cr.moveToNext());
			}
	        cronTaskList = taskList;
	        cr.close();
		}
		
		return cronTaskList;
	} 
	
	/**
	 * 根据Id取得相应的CronTask
	 * @param id
	 * @return
	 */
	public static CronTask getCronTaskById(Context context, long id) {
		List<CronTask> taskList = getAllCronTask(context);
		for(CronTask task : taskList) {
			if (id==task.id) return task;
		}
		return null;
	}
	
	/**
	 * 取得一段时间内最近的一次任务应该在多少分钟后被执行
	 * 
	 * @param taskList
	 * @param time 查询的时间段,单位分钟 如60则查询未来一小时内是否有Task应该被执行
	 * @return
	 */
	public static Calendar getNextTrigger(
			List<CronTask> taskList, Calendar currentTime, int interval) {
		//初始化时间
		Calendar cal = Calendar.getInstance();
		cal.setTimeInMillis(currentTime.getTimeInMillis());
		cal.set(Calendar.MILLISECOND, 0);
		cal.set(Calendar.SECOND, 0);
		
		int minute;	int hour;
		int dom;	int dow;
		int month;	int year;
		
		for(int i=0; i<interval; i++) {
			cal.add(Calendar.MINUTE, 1);
			minute = cal.get(Calendar.MINUTE);
			hour   = cal.get(Calendar.HOUR_OF_DAY);
			dom    = cal.get(Calendar.DAY_OF_MONTH);
			dow    = cal.get(Calendar.DAY_OF_WEEK);
			month  = cal.get(Calendar.MONTH);
			year   = cal.get(Calendar.YEAR);

			for (CronTask task : taskList) {
				boolean match = task.isEnabled() &&
							task.bYears[year] &&
							task.bMonths[month] &&
							(task.isByDow()?task.bDaysOfMonth[dom]:task.bDaysOfWeek[dow]) &&
							task.bHours[hour] &&
							task.bMinutes[minute];
				if (match) return cal;
			}	
		}
		
		//如果没有匹配的任务,就返回time后的日期,那个时候继续查询下一时间段的任务
		return cal;
	}
	
	/**
	 * 添加任务
	 * @param context
	 * @param task
	 * @return
	 */
	public static int addTask(Context context, CronTask task){
		Log.d(Consts.TAG, "Task Helper addTask");
		ContentResolver resolver = context.getContentResolver();
		ContentValues values = createContentValues(task);
		
		Uri uri = resolver.insert(CronTask.CONTENT_URI, values);
		String id = uri.getPathSegments().get(1);
		
		setCronTaskList(null);
		
		return Integer.parseInt(id);
	}
	
	/**
	 * 修改任务
	 * @param context
	 * @param task
	 * @return
	 */
	public static int updateTask(Context context, CronTask task) {
		Log.d(Consts.TAG, "Task Helper updateTask ID:"+task.id);
		ContentResolver resolver = context.getContentResolver();
		ContentValues values = createContentValues(task);
		
		setCronTaskList(null);
		
		Uri uri = ContentUris.withAppendedId(CronTask.CONTENT_URI, task.id);
		int ret = resolver.update(uri, values, null, null);
		setNextTask(context);
		return ret;
	}
	
	/**
	 * 删除任务
	 * @param context
	 * @param alarmId
	 */
    public static void deleteTask(Context context, int taskId) {
    	Log.d(Consts.TAG, "Task Helper deleteTask ID:"+taskId);
        ContentResolver contentResolver = context.getContentResolver();
        /* If alarm is snoozing, lose it */
        //disableSnoozeAlert(context, taskId);

        Uri uri = ContentUris.withAppendedId(CronTask.CONTENT_URI, taskId);
        contentResolver.delete(uri, "", null);
        setCronTaskList(null);
        setNextTask(context);
    }
	
	/**
	 * 把AlarmTask的内容写入ContentValues类,以用于数据库写入和更新
	 * @param alarm
	 * @return
	 */
	public static ContentValues createContentValues(CronTask task) {
		ContentValues values = new ContentValues(10);
		
		values.put(CronTask.Columns.ENABLED, task.enabled);
		values.put(CronTask.Columns.TASK_TYPE, task.getClass().getName());//用类名作为TYPE
		values.put(CronTask.Columns.TITLE, task.title);
		values.put(CronTask.Columns.DESCRIPTION, task.description);
		values.put(CronTask.Columns.CRON_PATTEN, task.unparse());
		values.put(CronTask.Columns.STARTDATE, task.startDate);
		values.put(CronTask.Columns.ENDDATE, task.endDate);
		values.put(CronTask.Columns.ENABLED, task.enabled);
		values.put(CronTask.Columns.BY_DOW, task.byDow);
		values.put(CronTask.Columns.EXTRA, task.extra.toString());
		
		return values;
	}
	
	public static void setCronTaskList(List<CronTask> list) {
		cronTaskList = list;
	}
}
